iT邦幫忙

2022 iThome 鐵人賽

DAY 17
0

Review

昨日我們講解了JdbcTemplate剩下CRUD的部分,也說明了它跟Java Bean之間如何應用。

今日我們將進入重頭戲,declarative transaction management,在這之前我們先簡介一下何謂Transaction與Transaction managemet的兩種方式,最後以一個例子說明沒有事務管理會發生的情況。

Transaction

Transaction是指對資料庫進行一連串的操作,必須全部成功否則全部回到未執行的狀態。以銀行轉帳的例子來說,A帳戶轉入100元到B帳戶,必須執行兩個SQL語法,分別是A帳戶扣款100元與B帳戶轉入100元,兩個指令必須同時成立,否則皆未執行。

ACID properties of transactions

原子性 Atomicity

整個交易視為一個執行單元,具有不可分割性,要就全部成功,不然就全部取消。

一致性 Consistency

交易完成後,寫入的資料須符合所有既定的規則,如constraints,cascades,triggers等

隔離性 Isolation

Transaction在執行時往往是併發(concurrently)執行,可能多個transaction在操作相同的資料,因此transaction需要適度隔離,以免彼此互相影響。

持久性 Durability

交易完成即代表數據修改永久保存下來,不因系統斷線、當機而受影響。

Transaction management

交易管理可以分為兩種方式,如下

Programmatic Transaction Management

過去經典轉帳

Connection con = null;
String sql1 = "UPDATE ACCOUNT SET BALANCE = BALANCE -100 WHERE id = 1";
String sql2 = "UPDATE ACCOUNT SET BALANCE = BALANCE +100 WHERE id = 2"; 
PrepareStatement ps = null
try{
    //取得資料庫連線
    con = JDBCUtils.getConnection();
    //設定非自動提交
    con.setAutoCommit(false);
    ps = con.prepareStatement(sql1);
    ps.executeUpdate();
    ps = con.prepareStatement(sql2);
    ps.executeUpdate();
    //提交
    con.commit()
}catch(Exception e){
    con.rollback();
    e.printStackTrace();
}finally{
    //關閉連線資源
    JDBCUtils.close();
}

現在可以透過Spring TransactionTemplate來簡化操作

Declarative Transaction Management

由於事務管理的程非常固定,可以作為一種Cross-cutting concerns,可透過AOP的方式來達成。Spring已替我們完成transaction的aspect,我們只需透過幾個設定就能使用,之後也將著重於聲明式事務作介紹。

UserService{
    @Transaction
    public void doTransfer(){
        ...
    }
}

測試無事務管理的情況

建立Account資料表

CREATE TABLE ACCOUNT(
   ACCOUNT_ID  NVARCHAR(10) NOT NULL,
    BALANCE INT
)

INSERT INTO ACCOUNT VALUES ('1',1000);
INSERT INTO ACCOUNT VALUES ('2',1000);

建立Account Java Bean

public class Account {
    private String accountId;
    private Integer balance;
    //getter setter toString 略
}

創建Dao

@Repository
public class AccountDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void addMoney(String accountId,Integer amount){
        String sql = "UPDATE ACCOUNT SET BALANCE = BALANCE +? WHERE ACCOUNT_ID = ?";
        jdbcTemplate.update(sql,amount,accountId);
    }

    public void minusMoney(String accountId,Integer amount){
        String sql = "UPDATE ACCOUNT SET BALANCE = BALANCE -? WHERE ACCOUNT_ID = ?";
        jdbcTemplate.update(sql,amount,accountId);
    }
}

創建Transaction會有異常狀況的Service

@Service
public class AccountService {
    @Autowired
    private AccountDao accountDao;
    public void transferMoney(String from, String to , Integer amount){
        accountDao.addMoney(to,amount);
        int a =1/0;
        accountDao.minusMoney(from,amount);
        System.out.println("轉帳完成:"+from+" to "+to+" 金額:"+amount);
    }
}

Result
僅有帳戶2被加到錢,帳戶1未扣錢
https://ithelp.ithome.com.tw/upload/images/20221010/20128084J5zaN4QLA1.jpg
https://ithelp.ithome.com.tw/upload/images/20221010/20128084IhZqe43s2Q.jpg

Reference


上一篇
Day24 - JdbcTemplate (2)
下一篇
Day26 - Declarative transaction management (2)
系列文
這些年,我們早該學會的Spring Framework30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言